package com.zj.ckproxy.handler;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONValidator;
import com.zj.baseproxy.enums.TypeEnum;
import com.zj.baseproxy.interfaces.HttpHandler;
import com.zj.baseproxy.model.Page;
import com.zj.baseproxy.model.PageInfo;
import com.zj.baseproxy.utils.ClassUtil;
import com.zj.ckproxy.utils.FieldUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author arthur_zhou
 * @date 2024/2/28 15:03
 */
@Slf4j
public class CkHandler {

    @Resource
    private HttpHandler httpHandler;

    /**
     * 组装返回结果
     *
     * @param id            方法全路径
     * @param url           请求路径
     * @param sql           sql
     * @param xmlResultType xml里的resultType
     * @param returnType    方法上的返回class
     * @return 结果
     */
    public <T> T packageResult(String id, String url, String sql, Class<?> xmlResultType, Class<T> returnType) {
        List<?> dataList = executeSql(id, url, sql, xmlResultType);
        // xml里的class和方法里的class一致，返回第一个
        if (ClassUtil.getWrapClass(xmlResultType) == ClassUtil.getWrapClass(returnType)) {
            return ClassUtil.cast(CollectionUtil.isEmpty(dataList) ? null : dataList.get(0), returnType);
        }
        if (List.class == returnType) {
            return returnType.cast(dataList);
        } else if (Set.class == returnType) {
            return returnType.cast(new HashSet<>(dataList));
        } else if (Page.class == returnType) {
            log.debug("{}没有传入分页信息", id);
            return returnType.cast(Page.setPageData(dataList));
        }
        log.debug("{}数据映射失败返回null", id);
        return ClassUtil.cast(null, returnType);
    }


    /**
     * 执行sql
     *
     * @param id    方法全路径
     * @param url   请求路径
     * @param sql   sql
     * @param clazz 数组类型
     * @return 返回的二维数组
     */
    public <T> List<T> executeSql(String id, String url, String sql, Class<T> clazz) {
        if (StringUtils.isEmpty(url)) {
            log.debug("{}请求路径为空", id);
            return Collections.emptyList();
        }
        if (StringUtils.isEmpty(sql)) {
            log.debug("{}的sql为空", id);
            return Collections.emptyList();
        }
        List<T> ckModelList = new ArrayList<>();
        // 执行sql
        JSONArray resultArray = executeSql(url, sql);
        if (CollectionUtil.isEmpty(resultArray)) {
            return ckModelList;
        }
        // 是基础类型时，返回第一列
        if (ClassUtil.isBaseType(clazz)) {
            for (int i = 0; i < resultArray.size(); i++) {
                ckModelList.add(resultArray.getJSONArray(i).getObject(0, clazz));
            }
            return ckModelList;
        }
        // 获取属性上的@CkField注解与属性名对应关系
        Map<Integer, String> fieldMap = FieldUtil.getFieldMap(clazz);
        for (int i = 0; i < resultArray.size(); i++) {
            JSONArray childArray = resultArray.getJSONArray(i);
            JSONObject ckModeJson = new JSONObject();
            for (int j = 0; j < childArray.size(); j++) {
                // 获取属性名
                String fieldName = fieldMap.get(j);
                // 获取属性值
                Object fieldValue = childArray.get(j);
                if (Objects.nonNull(fieldName)) {
                    ckModeJson.put(fieldName, fieldValue);
                }
            }
            ckModelList.add(ckModeJson.toJavaObject(clazz));
        }
        return ckModelList;
    }

    /**
     * 执行sql
     *
     * @param url 请求路径
     * @param sql 请求sql
     * @return 二维数组
     */
    public JSONArray executeSql(String url, String sql) {
        String ckResponse = httpHandler.post(TypeEnum.CK, url, JSON.toJSONString(Collections.singletonMap("sql", sql)));
        if (StringUtils.isEmpty(ckResponse)
                || !JSONValidator.Type.Object.equals(JSONValidator.from(ckResponse).getType())) {
            log.error("ck响应解析错误：{}", ckResponse);
            return null;
        }
        JSONObject jsonObject = JSONObject.parseObject(ckResponse);
        if (CollectionUtil.isEmpty(jsonObject)) {
            return null;
        }
        String code = jsonObject.getString("code");
        if (!"0".equals(code)) {
            log.error("code码错误{}", ckResponse);
            return null;
        }
        String dataStr = jsonObject.getString("result");
        if (StringUtils.isEmpty(dataStr)
                || !JSONValidator.Type.Array.equals(JSONValidator.from(dataStr).getType())) {
            log.error("ck响应错误：{}", ckResponse);
            return null;
        }
        return jsonObject.getJSONArray("result");
    }

    /**
     * 组装分页返回结果
     *
     * @param id            方法全路径
     * @param url           ck请求路径
     * @param sql           sql
     * @param xmlResultType xml里的resultType
     * @param returnType    方法上的返回class
     * @param pageInfo      分页信息
     * @return 结果
     */
    public <T> T packagePage(String id, String url, String sql, Class<?> xmlResultType, Class<T> returnType, PageInfo pageInfo) {
        if (Objects.isNull(pageInfo)) {
            return packageResult(id, url, sql, xmlResultType, returnType);
        }
        int from = (pageInfo.getPageNum() - 1) * pageInfo.getPageSize();
        String dataSql = String.format("select * from (%s) a limit %s,%s", sql, from, pageInfo.getPageSize());
        // 返回类型是Page，带上总数
        if (Page.class == returnType) {
            List<?> list = packageResult(id, url, dataSql, xmlResultType, List.class);
            Long total = packageResult(id, url, String.format("select count(1) from (%s) a", sql), Long.class, Long.class);
            return returnType.cast(Page.setPageData(list, total));
        }
        return packageResult(id, url, dataSql, xmlResultType, returnType);
    }
}
